/**
 * author: vformAdmin
 * email: vdpadmin@163.com
 * website: https://www.vform666.com
 * date: 2021.08.18
 * remark: 如果要分发VForm源码，需在本文件顶部保留此文件头信息！！
 */

import {
  deepClone,
  generateId,
  getDefaultFormConfig,
  overwriteObj,
  traverseWidgetsOfContainer,
} from '@/utils/util'
import {
  containers,
  advancedFields,
  basicFields,
  customFields,
  chartContainers,
  chartWidgets,
} from '@/components/form-designer/widget-panel/widgetsConfig.js'
import { VARIANT_FORM_VERSION } from '@/utils/config'
import eventBus from '@/utils/event-bus'
import { loadFormJson } from '@/api/form'
import type { FormDesigner, FormConfig } from '@/types/form'
import { ServiceVersionVOType } from '@coolphk/shared-types/low-code'
import { getCurrentServiceVersionVOByServiceId } from '@/api/serviceVersion'
import { ElNotification } from 'element-plus'

export function createDesigner(vueInstance): FormDesigner {
  // let defaultFormConfig = deepClone(getDefaultFormConfig())
  let defaultFormConfig: FormConfig = getDefaultFormConfig()

  return {
    widgetList: [],
    formConfig: { cssCode: '' },

    selectedId: null,
    selectedWidget: null,
    selectedWidgetName: null, //选中组件名称（唯一）
    vueInstance: vueInstance,

    formWidget: null, //表单设计容器

    cssClassList: [], //自定义样式列表

    historyData: {
      index: -1, //index: 0,
      maxStep: 20,
      steps: [],
    },
    currentServiceVersionVOs: [], //当前表单相关的发布服务版本集合

    /**
     * 初始化设计器方法
     * 该方法用于重置当前表单设计环境到初始状态，包括清空组件列表和表单配置，并根据需要加载历史数据或当前发布服务版本
     *
     * @param resetFormJson - 一个布尔值，指示是否需要重置表单JSON如果为false或未提供，则会初始化历史数据和加载当前发布服务版本
     */
    initDesigner(resetFormJson: boolean) {
      // 初始化组件列表为空数组
      this.widgetList = []
      // 深拷贝默认表单配置到当前表单配置
      this.formConfig = deepClone(defaultFormConfig)

      // //输出版本信息和语雀链接
      // console.info(`%cVariantForm %cVer${VARIANT_FORM_VERSION} %chttps://www.yuque.com/visualdev/vform3`,
      //     "color:#409EFF;font-size: 22px;font-weight:bolder",
      //     "color:#999;font-size: 12px",
      //     "color:#333"
      // )

      // 如果不提供重置表单JSON或其值为false，则执行以下操作
      if (!resetFormJson) {
        // 初始化历史数据，以便能够回滚到先前的表单设计状态
        this.initHistoryData()
        // 加载当前发布的服务版本信息，用来和表单当前的服务版本进行比较
        this.loadCurrentServiceVersionVOS().then(() => {
          this.compareServiceVersions()
        })
      }
    },
    compareServiceVersions() {
      this.formConfig.serviceVersionVOs.map((formServiceVersionVO: ServiceVersionVOType, index: number) => {
        // console.log('compareServiceVersions')

        if (formServiceVersionVO.id != this.currentServiceVersionVOs[index].id) {
          formServiceVersionVO.isOld = true //判断版本是否变更，该字段在服务列表处显示new标识
          /*ElNotification({
            title: '提示',
            message: `表单关联的服务《${formServiceVersionVO.service.name}》版本已变更，请及时更新！`,
            type: 'warning',
            duration: 5000,
          })*/
        }
      })
      console.log('this.formConfig.serviceVersionVOs', this.formConfig.serviceVersionVOs)
    },
    clearDesigner(skipHistoryChange) {
      let emptyWidgetListFlag = this.widgetList.length === 0
      this.widgetList = []
      this.selectedId = null
      this.selectedWidgetName = null
      this.selectedWidget = {} //this.selectedWidget = null
      overwriteObj(this.formConfig, defaultFormConfig) //

      if (!!skipHistoryChange) {
        //什么也不做！！
      } else if (!emptyWidgetListFlag) {
        this.emitHistoryChange()
      } else {
        this.saveCurrentHistoryStep()
      }
    },

    loadPresetCssCode(preCssCode) {
      if (this.formConfig.cssCode === '' && !!preCssCode) {
        this.formConfig.cssCode = preCssCode
      }
    },

    getLayoutType() {
      return this.formConfig.layoutType || 'PC'
    },

    changeLayoutType(newType) {
      this.formConfig.layoutType = newType
    },

    getImportTemplate() {
      return {
        widgetList: [],
        //formConfig: deepClone(this.formConfig)
        formConfig: deepClone(defaultFormConfig),
      }
    },

    loadFormJson(formJson) {
      let modifiedFlag = false
      console.log('loadFormJson', formJson)
      if (!!formJson && !!formJson.widgetList) {
        this.formWidget.clearWidgetRefList()
        this.widgetList = formJson.widgetList
        modifiedFlag = true
      }
      if (!!formJson && !!formJson.formConfig) {
        //this.formConfig = importObj.formConfig
        overwriteObj(
          this.formConfig,
          formJson.formConfig,
        ) /* 用=赋值，会导致inject依赖注入的formConfig属性变成非响应式 */
        modifiedFlag = true
      }

      if (modifiedFlag) {
        this.emitEvent('form-json-imported', []) // 知其他组
      }

      return modifiedFlag
    },

    setSelected(selected) {
      console.log('setSelected')
      if (!selected) {
        this.clearSelected()
        return
      }

      this.selectedWidget = selected
      if (!!selected.id) {
        this.selectedId = selected.id
        this.selectedWidgetName = selected.options.name

        /*if (!selected.category) {
          // 如果是选中字段组件
          this.emitEvent('canvas-select-field', selected.options.name)
        }*/
      }
    },

    updateSelectedWidgetNameAndLabel(selectedWidget, newName, newLabel) {
      this.selectedWidgetName = newName
      if (!!newLabel && Object.keys(selectedWidget.options).indexOf('label') > -1) {
        selectedWidget.options.label = newLabel
      }
    },

    clearSelected() {
      this.selectedId = null
      this.selectedWidgetName = null
      this.selectedWidget = {} //this.selectedWidget = null
    },

    checkWidgetMove(evt) {
      /* Only field widget can be dragged into sub-form */
      if (!!evt.draggedContext && !!evt.draggedContext.element) {
        let wgCategory = evt.draggedContext.element.category
        let wgType = evt.draggedContext.element.type + ''

        console.log('evt to className: ', evt.to.className)
        if (!!evt.to) {
          /* 单行子表单只允许拖入容器组件！！ */
          if (evt.to.className === 'sub-form-drag-drop-zone' && wgCategory === 'container') {
            //this.$message.info(this.vueInstance.i18nt('designer.hint.onlyFieldWidgetAcceptable'))
            return false
          }

          /* 多行子表单只允许拖入栅格组件！！ */
          if (evt.to.className === 'grid-sub-form-drag-drop-zone' && wgType !== 'grid') {
            return false
          }

          /* 弹窗不允许多层嵌套，弹窗也不允许和抽屉相互嵌套 */
          if (
            evt.to.className === 'vf-dialog-drop-zone' &&
            (wgType === 'vf-dialog' || wgType === 'vf-drawer')
          ) {
            return false
          }

          /* 抽屉不允许多层嵌套，抽屉也不允许和弹窗相互嵌套 */
          if (
            evt.to.className === 'vf-drawer-drop-zone' &&
            (wgType === 'vf-dialog' || wgType === 'vf-drawer')
          ) {
            return false
          }

          /* 弹窗、抽屉只允许拖入设计器画布第一层！！ */
          if (
            evt.to.className !== 'form-widget-canvas' &&
            evt.to.className !== 'canvas-drag-drop-zone' &&
            (wgType === 'vf-dialog' || wgType === 'vf-drawer')
          ) {
            return false
          }

          /* 对象器不允许拖入子表单、弹窗和抽屉，对象容器自身也不允许嵌套 */
          if (
            evt.to.className === 'object-group-drag-drop-zone' &&
            (wgType === 'object-group' ||
              wgType === 'sub-form' ||
              wgType === 'grid-sub-form' ||
              wgType === 'table-sub-form' ||
              wgType === 'vf-dialog' ||
              wgType === 'vf-drawer')
          ) {
            return false
          }
          /*数据表格只允许拖入非容器组件*/
          if (evt.to.className === 'table-column-drag-drop-zone' && wgCategory === 'container') {
            return false
          }
        }
      }

      return true
    },

    checkFieldMove(evt) {
      console.log('checkFieldMove', evt)
      if (!!evt.draggedContext && !!evt.draggedContext.epement) {
        let wgCategory = evt.draggedContext.epement.category
        let wgType = evt.draggedContext.epement.type + ''
        if (!!evt.to) {
          /* 插槽不允许被拖入单行子表单、多行容器 */
          if (
            (evt.to.className === 'sub-form-table' || evt.to.className === 'grid-sub-form') &&
            wgType === 'slot'
          ) {
            //this.$message.info(this.vueInstance.i18nt('designer.hint.onlyFieldWidgetAcceptable'))
            return false
          }

          /* 行子表单只允许拖入栅格组件！！ */
          if (evt.to.className === 'grid-sub-form' && wgType !== 'grid') {
            return false
          }
        }
      }

      return true
    },

    /**
     * 追加表格新行
     * @param widget
     */
    appendTableRow(widget) {
      let rowIdx = widget.rows.length //确定插入���位置
      let newRow = deepClone(widget.rows[widget.rows.length - 1])
      newRow.id = 'table-row-' + generateId()
      newRow.merged = false
      newRow.cols.forEach((col: any) => {
        col.id = 'table-cell-' + generateId()
        col.options.name = col.id
        col.merged = false
        col.options.colspan = 1
        col.options.rowspan = 1
        col.widgetList.length = 0
      })
      widget.rows.splice(rowIdx, 0, newRow)

      this.emitHistoryChange()
    },

    /**
     * 追加表格新列
     * @param widget
     */
    appendTableCol(widget) {
      let colIdx = widget.rows[0].cols.length //确定插入列位置
      widget.rows.forEach((row: any) => {
        let newCol = deepClone(this.getContainerByType('table-cell'))
        newCol.id = 'table-cell-' + generateId()
        newCol.options.name = newCol.id
        newCol.merged = false
        newCol.options.colspan = 1
        newCol.options.rowspan = 1
        newCol.widgetList.length = 0
        row.cols.splice(colIdx, 0, newCol)
      })

      this.emitHistoryChange()
    },

    insertTableRow(widget, insertPos, cloneRowIdx, curCol, aboveFlag) {
      let newRowIdx = !!aboveFlag ? insertPos : insertPos + 1 //初步确定插入行位置
      if (!aboveFlag) {
        //继续向下寻找同列第一个未被合并的单元格
        let tmpRowIdx = newRowIdx
        let rowFoundFlag = false
        while (tmpRowIdx < widget.rows.length) {
          if (!widget.rows[tmpRowIdx].cols[curCol].merged) {
            newRowIdx = tmpRowIdx
            rowFoundFlag = true
            break
          } else {
            tmpRowIdx++
          }
        }

        if (!rowFoundFlag) {
          newRowIdx = widget.rows.length
        }
      }

      let newRow = deepClone(widget.rows[cloneRowIdx])
      newRow.id = 'table-row-' + generateId()
      newRow.merged = false
      newRow.cols.forEach((col) => {
        col.id = 'table-cell-' + generateId()
        col.options.name = col.id
        col.merged = false
        col.options.colspan = 1
        col.options.rowspan = 1
        col.widgetList.length = 0
      })
      widget.rows.splice(newRowIdx, 0, newRow)

      let colNo = 0
      while (newRowIdx < widget.rows.length - 1 && colNo < widget.rows[0].cols.length) {
        //界判断
        const cellOfNextRow = widget.rows[newRowIdx + 1].cols[colNo]
        const rowMerged = cellOfNextRow.merged //确定插入位置下一行的单元格是否为合并单元格
        if (!!rowMerged) {
          let rowArray = widget.rows
          let unMergedCell = {} as any
          let startRowIndex = null
          for (let i = newRowIdx; i >= 0; i--) {
            //查找该行已合并的主单元格
            if (!rowArray[i].cols[colNo].merged && rowArray[i].cols[colNo].options.rowspan > 1) {
              startRowIndex = i
              unMergedCell = rowArray[i].cols[colNo]
              break
            }
          }

          if (!!unMergedCell.options) {
            //如果有符合条件的unMergedCell
            let newRowspan = unMergedCell.options.rowspan + 1
            this.setPropsOfMergedRows(
              widget.rows,
              startRowIndex,
              colNo,
              unMergedCell.options.colspan,
              newRowspan,
            )
            colNo += unMergedCell.options.colspan
          } else {
            colNo += 1
          }
        } else {
          //colNo += 1
          colNo += cellOfNextRow.options.colspan || 1
        }
      }

      this.emitHistoryChange()
    },

    insertTableCol(widget, insertPos, curRow, leftFlag) {
      let newColIdx = !!leftFlag ? insertPos : insertPos + 1 //初步确定插入列位置
      if (!leftFlag) {
        //继续向右寻找同行第一个未被合并的单元格
        let tmpColIdx = newColIdx
        let colFoundFlag = false
        while (tmpColIdx < widget.rows[curRow].cols.length) {
          if (!widget.rows[curRow].cols[tmpColIdx].merged) {
            newColIdx = tmpColIdx
            colFoundFlag = true
            break
          } else {
            tmpColIdx++
          }

          if (!colFoundFlag) {
            newColIdx = widget.rows[curRow].cols.length
          }
        }
      }

      widget.rows.forEach((row) => {
        let newCol = deepClone(this.getContainerByType('table-cell'))
        newCol.id = 'table-cell-' + generateId()
        newCol.options.name = newCol.id
        newCol.merged = false
        newCol.options.colspan = 1
        newCol.options.rowspan = 1
        newCol.widgetList.length = 0
        row.cols.splice(newColIdx, 0, newCol)
      })

      let rowNo = 0
      while (newColIdx < widget.rows[0].cols.length - 1 && rowNo < widget.rows.length) {
        //越界判断
        const cellOfNextCol = widget.rows[rowNo].cols[newColIdx + 1]
        const colMerged = cellOfNextCol.merged //确定插入位置右侧的单元格是否为并单元格
        if (!!colMerged) {
          let colArray = widget.rows[rowNo].cols
          let unMergedCell = {
            options: undefined,
          }
          let startColIndex = null
          for (let i = newColIdx; i >= 0; i--) {
            //查找该行已合并的主单元格
            if (!colArray[i].merged && colArray[i].options.colspan > 1) {
              startColIndex = i
              unMergedCell = colArray[i]
              break
            }
          }

          if (!!unMergedCell.options) {
            //如果有符合条件的unMergedCell
            let newColspan = unMergedCell.options.colspan + 1
            this.setPropsOfMergedCols(
              widget.rows,
              rowNo,
              startColIndex,
              newColspan,
              unMergedCell.options.rowspan,
            )
            rowNo += unMergedCell.options.rowspan
          } else {
            rowNo += 1
          }
        } else {
          //rowNo += 1
          rowNo += cellOfNextCol.options.rowspan || 1
        }
      }

      this.emitHistoryChange()
    },

    setPropsOfMergedCols(rowArray, startRowIndex, startColIndex, newColspan, rowspan) {
      for (let i = startRowIndex; i < startRowIndex + rowspan; i++) {
        for (let j = startColIndex; j < startColIndex + newColspan; j++) {
          if (i === startRowIndex && j === startColIndex) {
            rowArray[i].cols[j].options.colspan = newColspan //合并后的主单元格
            continue
          }

          rowArray[i].cols[j].merged = true
          rowArray[i].cols[j].options.colspan = newColspan
          rowArray[i].cols[j].widgetList = []
        }
      }
    },

    setPropsOfMergedRows(rowArray, startRowIndex, startColIndex, colspan, newRowspan) {
      for (let i = startRowIndex; i < startRowIndex + newRowspan; i++) {
        for (let j = startColIndex; j < startColIndex + colspan; j++) {
          if (i === startRowIndex && j === startColIndex) {
            rowArray[i].cols[j].options.rowspan = newRowspan
            continue
          }

          rowArray[i].cols[j].merged = true
          rowArray[i].cols[j].options.rowspan = newRowspan
          rowArray[i].cols[j].widgetList = []
        }
      }
    },

    setPropsOfSplitCol(rowArray, startRowIndex, startColIndex, colspan, rowspan) {
      for (let i = startRowIndex; i < startRowIndex + rowspan; i++) {
        for (let j = startColIndex; j < startColIndex + colspan; j++) {
          rowArray[i].cols[j].merged = false
          rowArray[i].cols[j].options.rowspan = 1
          rowArray[i].cols[j].options.colspan = 1
        }
      }
    },

    setPropsOfSplitRow(rowArray, startRowIndex, startColIndex, colspan, rowspan) {
      for (let i = startRowIndex; i < startRowIndex + rowspan; i++) {
        for (let j = startColIndex; j < startColIndex + colspan; j++) {
          rowArray[i].cols[j].merged = false
          rowArray[i].cols[j].options.rowspan = 1
          rowArray[i].cols[j].options.colspan = 1
        }
      }
    },

    mergeTableCol(rowArray, colArray, curRow, curCol, leftFlag, cellWidget) {
      let mergedColIdx = !!leftFlag ? curCol : curCol + colArray[curCol].options.colspan

      // let remainedColIdx = !!leftFlag ? curCol - colArray[curCol - 1].options.colspan : curCol
      let remainedColIdx = !!leftFlag ? curCol - 1 : curCol
      if (!!leftFlag) {
        //继续向左寻找同行未被合并的第一个单元格
        let tmpColIdx = remainedColIdx
        while (tmpColIdx >= 0) {
          if (!rowArray[curRow].cols[tmpColIdx].merged) {
            remainedColIdx = tmpColIdx
            break
          } else {
            tmpColIdx--
          }
        }
      }

      if (!!colArray[mergedColIdx].widgetList && colArray[mergedColIdx].widgetList.length > 0) {
        //保留widgetList
        if (
          !colArray[remainedColIdx].widgetList ||
          colArray[remainedColIdx].widgetList.length === 0
        ) {
          colArray[remainedColIdx].widgetList = deepClone(colArray[mergedColIdx].widgetList)
        }
      }

      let newColspan =
        colArray[mergedColIdx].options.colspan * 1 + colArray[remainedColIdx].options.colspan * 1
      this.setPropsOfMergedCols(
        rowArray,
        curRow,
        remainedColIdx,
        newColspan,
        cellWidget.options.rowspan,
      )

      this.emitHistoryChange()
    },

    mergeTableWholeRow(rowArray, colArray, rowIndex, colIndex) {
      //需要考虑操作的行存在已合并的单元格！！
      //整行所有单元格行高不一致不可合并！！
      let startRowspan = rowArray[rowIndex].cols[0].options.rowspan
      let unmatchedFlag = false
      for (let i = 1; i < rowArray[rowIndex].cols.length; i++) {
        if (rowArray[rowIndex].cols[i].options.rowspan !== startRowspan) {
          unmatchedFlag = true
          break
        }
      }
      if (unmatchedFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.rowspanNotConsistentForMergeEntireRow'),
        )
        return
      }

      let widgetListCols = colArray.filter((colItem) => {
        return !colItem.merged && !!colItem.widgetList && colItem.widgetList.length > 0
      })
      if (!!widgetListCols && widgetListCols.length > 0) {
        //保留widgetList
        if (
          widgetListCols[0].id !== colArray[0].id &&
          (!colArray[0].widgetList || colArray[0].widgetList.length <= 0)
        ) {
          colArray[0].widgetList = deepClone(widgetListCols[0].widgetList)
        }
      }

      this.setPropsOfMergedCols(
        rowArray,
        rowIndex,
        0,
        colArray.length,
        colArray[colIndex].options.rowspan,
      )

      this.emitHistoryChange()
    },

    mergeTableRow(rowArray, curRow, curCol, aboveFlag, cellWidget) {
      let mergedRowIdx = !!aboveFlag ? curRow : curRow + cellWidget.options.rowspan

      //let remainedRowIdx = !!aboveFlag ? curRow - cellWidget.options.rowspan : curRow
      let remainedRowIdx = !!aboveFlag ? curRow - 1 : curRow
      if (!!aboveFlag) {
        //继续向上寻找同列未被合并的第一个单元格
        let tmpRowIdx = remainedRowIdx
        while (tmpRowIdx >= 0) {
          if (!rowArray[tmpRowIdx].cols[curCol].merged) {
            remainedRowIdx = tmpRowIdx
            break
          } else {
            tmpRowIdx--
          }
        }
      }

      if (
        !!rowArray[mergedRowIdx].cols[curCol].widgetList &&
        rowArray[mergedRowIdx].cols[curCol].widgetList.length > 0
      ) {
        //保留widgetList
        if (
          !rowArray[remainedRowIdx].cols[curCol].widgetList ||
          rowArray[remainedRowIdx].cols[curCol].widgetList.length === 0
        ) {
          rowArray[remainedRowIdx].cols[curCol].widgetList = deepClone(
            rowArray[mergedRowIdx].cols[curCol].widgetList,
          )
        }
      }

      let newRowspan =
        rowArray[mergedRowIdx].cols[curCol].options.rowspan * 1 +
        rowArray[remainedRowIdx].cols[curCol].options.rowspan * 1
      this.setPropsOfMergedRows(
        rowArray,
        remainedRowIdx,
        curCol,
        cellWidget.options.colspan,
        newRowspan,
      )

      this.emitHistoryChange()
    },

    mergeTableWholeCol(rowArray, colArray, rowIndex, colIndex) {
      //需要考虑操作的列存在已合并的单元格！！
      //整列所有单元格列宽不一致不可合并！！
      let startColspan = rowArray[0].cols[colIndex].options.colspan
      let unmatchedFlag = false
      for (let i = 1; i < rowArray.length; i++) {
        if (rowArray[i].cols[colIndex].options.colspan !== startColspan) {
          unmatchedFlag = true
          break
        }
      }
      if (unmatchedFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.colspanNotConsistentForMergeEntireColumn'),
        )
        return
      }

      let widgetListCols = []
      rowArray.forEach((rowItem) => {
        let tempCell = rowItem.cols[colIndex]
        if (!tempCell.merged && !!tempCell.widgetList && tempCell.widgetList.length > 0) {
          widgetListCols.push(tempCell)
        }
      })

      let firstCellOfCol = rowArray[0].cols[colIndex]
      if (!!widgetListCols && widgetListCols.length > 0) {
        //保留widgetList
        if (
          widgetListCols[0].id !== firstCellOfCol.id &&
          (!firstCellOfCol.widgetList || firstCellOfCol.widgetList.length <= 0)
        ) {
          firstCellOfCol.widgetList = deepClone(widgetListCols[0].widgetList)
        }
      }

      this.setPropsOfMergedRows(
        rowArray,
        0,
        colIndex,
        firstCellOfCol.options.colspan,
        rowArray.length,
      )

      this.emitHistoryChange()
    },

    undoMergeTableCol(rowArray, rowIndex, colIndex, colspan, rowspan) {
      this.setPropsOfSplitCol(rowArray, rowIndex, colIndex, colspan, rowspan)

      this.emitHistoryChange()
    },

    undoMergeTableRow(rowArray, rowIndex, colIndex, colspan, rowspan) {
      this.setPropsOfSplitRow(rowArray, rowIndex, colIndex, colspan, rowspan)

      this.emitHistoryChange()
    },

    deleteTableWholeCol(rowArray, colIndex) {
      //需考虑删除的是合并列！！
      let onlyOneColFlag = true
      rowArray.forEach((ri) => {
        if (ri.cols[0].options.colspan !== rowArray[0].cols.length) {
          onlyOneColFlag = false
        }
      })
      //仅剩一列则不可删除！！
      if (onlyOneColFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.lastColCannotBeDeleted'),
        )
        return
      }

      //整列所有单元格列宽不一致不可删除！！
      let startColspan = rowArray[0].cols[colIndex].options.colspan
      let unmatchedFlag = false
      for (let i = 1; i < rowArray.length; i++) {
        if (rowArray[i].cols[colIndex].options.colspan !== startColspan) {
          unmatchedFlag = true
          break
        }
      }
      if (unmatchedFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.colspanNotConsistentForDeleteEntireColumn'),
        )
        return
      }

      rowArray.forEach((rItem) => {
        rItem.cols.splice(colIndex, startColspan)
      })

      this.emitHistoryChange()
    },

    deleteTableWholeRow(rowArray, rowIndex) {
      //需考虑删除的是合并行！！
      let onlyOneRowFlag = true
      rowArray[0].cols.forEach((ci) => {
        if (ci.options.rowspan !== rowArray.length) {
          onlyOneRowFlag = false
        }
      })
      //仅剩行则不可删除！！
      if (onlyOneRowFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.lastRowCannotBeDeleted'),
        )
        return
      }

      //整行所有单元格行高不一致不可除！！
      let startRowspan = rowArray[rowIndex].cols[0].options.rowspan
      let unmatchedFlag = false
      for (let i = 1; i < rowArray[rowIndex].cols.length; i++) {
        if (rowArray[rowIndex].cols[i].options.rowspan !== startRowspan) {
          unmatchedFlag = true
          break
        }
      }
      if (unmatchedFlag) {
        this.vueInstance.$message.info(
          this.vueInstance.i18nt('designer.hint.rowspanNotConsistentForDeleteEntireRow'),
        )
        return
      }

      rowArray.splice(rowIndex, startRowspan)

      this.emitHistoryChange()
    },

    getContainerByType(typeName) {
      let allWidgets = [
        ...containers,
        ...basicFields,
        ...advancedFields,
        ...customFields,
        ...chartContainers,
        ...chartWidgets,
      ]
      let foundCon = null
      allWidgets.forEach((con) => {
        if (!!con.category && !!con.type && con.type === typeName) {
          foundCon = con
        }
      })

      return foundCon
    },

    getFieldWidgetByType(typeName) {
      let allWidgets = [
        ...containers,
        ...basicFields,
        ...advancedFields,
        ...customFields,
        ...chartContainers,
        ...chartWidgets,
      ]
      let foundWidget = null
      allWidgets.forEach((widget) => {
        if (!!!widget.category && !!widget.type && widget.type === typeName) {
          foundWidget = widget
        }
      })

      return foundWidget
    },

    hasConfig(widget, configName) {
      let originalWidget = null
      if (!!widget.category) {
        originalWidget = this.getContainerByType(widget.type)
      } else {
        originalWidget = this.getFieldWidgetByType(widget.type)
      }

      if (!originalWidget || !originalWidget.options) {
        return false
      }

      return Object.keys(originalWidget.options).indexOf(configName) > -1
    },

    upgradeWidgetConfig(oldWidget) {
      let newWidget = null
      if (!!oldWidget.category) {
        newWidget = this.getContainerByType(oldWidget.type)
      } else {
        newWidget = this.getFieldWidgetByType(oldWidget.type)
      }

      if (!newWidget || !newWidget.options) {
        return
      }

      Object.keys(newWidget.options).forEach((ck) => {
        if (!oldWidget.hasOwnProperty(ck)) {
          oldWidget.options[ck] = deepClone(newWidget.options[ck])
        }
      })
    },

    upgradeFormConfig(oldFormConfig) {
      Object.keys(this.formConfig).forEach((fc) => {
        if (!oldFormConfig.hasOwnProperty(fc)) {
          oldFormConfig[fc] = deepClone(this.formConfig[fc])
        }
      })
    },

    cloneGridCol(widget, parentWidget) {
      let newGridCol = deepClone(this.getContainerByType('grid-col'))
      newGridCol.options = deepClone(widget.options)
      let tmpId = generateId()
      newGridCol.id = 'grid-col-' + tmpId
      newGridCol.options.name = 'gridCol' + tmpId

      newGridCol.widgetList = deepClone(widget.widgetList)
      const fwHandler = (fw) => {
        fw.options.name = fw.type.replace(/-/g, '') + generateId()
        fw.id = fw.options.name
      }
      const cwHandler = (cw) => {
        cw.options.name = cw.type.replace(/-/g, '') + generateId()
        cw.id = cw.options.name
      }
      traverseWidgetsOfContainer(newGridCol, fwHandler, cwHandler)

      parentWidget.cols.push(newGridCol)
    },

    cloneContainer(containWidget) {
      if (containWidget.type === 'grid') {
        let newGrid = deepClone(this.getContainerByType('grid'))
        newGrid.id = newGrid.type + generateId()
        newGrid.options.name = newGrid.id
        containWidget.cols.forEach((gridCol) => {
          let newGridCol = deepClone(this.getContainerByType('grid-col'))
          let tmpId = generateId()
          newGridCol.id = 'grid-col-' + tmpId
          newGridCol.options.name = 'gridCol' + tmpId
          newGridCol.options.span = gridCol.options.span
          newGrid.cols.push(newGridCol)
        })

        return newGrid
      } else if (containWidget.type === 'table') {
        let newTable = deepClone(this.getContainerByType('table'))
        newTable.id = newTable.type + generateId()
        newTable.options.name = newTable.id
        containWidget.rows.forEach((tRow) => {
          let newRow = deepClone(tRow)
          newRow.id = 'table-row-' + generateId()
          newRow.cols.forEach((col) => {
            col.id = 'table-cell-' + generateId()
            col.options.name = col.id

            if (col.widgetList.length === 1) {
              const firstChildWidget = col.widgetList[0]
              if (!firstChildWidget.category) {
                //非容器组件
                const tempId = generateId()
                firstChildWidget.id = firstChildWidget.type.replace(/-/g, '') + tempId
                firstChildWidget.options.name = firstChildWidget.id
              } else {
                col.widgetList = [] //清空组件列表
              }
            } else {
              col.widgetList = [] //清空组件列表
            }
          })
          newTable.rows.push(newRow)
        })

        return newTable
      } else {
        //其他容器件不支持clone操作
        return null
      }
    },

    cloneFieldWidget(fieldWidget, parentList) {
      let newField = deepClone(fieldWidget)
      const tempId = generateId()
      newField.id = newField.type.replace(/-/g, '') + tempId
      newField.options.name = newField.id

      if (!!parentList) {
        parentList.push(newField)
      } else {
        this.widgetList.push(newField)
      }
    },

    moveUpWidget(parentList, indexOfParentList) {
      if (!!parentList) {
        if (indexOfParentList === 0) {
          this.vueInstance.$message(this.vueInstance.i18nt('designer.hint.moveUpFirstChildHint'))
          return
        }

        let tempWidget = parentList[indexOfParentList]
        parentList.splice(indexOfParentList, 1)
        parentList.splice(indexOfParentList - 1, 0, tempWidget)
      }
    },

    moveDownWidget(parentList, indexOfParentList) {
      if (!!parentList) {
        if (indexOfParentList === parentList.length - 1) {
          this.vueInstance.$message(this.vueInstance.i18nt('designer.hint.moveDownLastChildHint'))
          return
        }

        let tempWidget = parentList[indexOfParentList]
        parentList.splice(indexOfParentList, 1)
        parentList.splice(indexOfParentList + 1, 0, tempWidget)
      }
    },

    copyNewFieldWidget(origin) {
      console.log('clone')
      let newWidget = deepClone(origin)
      let tempId = generateId()
      newWidget.id = newWidget.type.replace(/-/g, '') + tempId
      //console.log('test id===', newWidget.id)

      if (!newWidget.nameReadonly) {
        newWidget.options.name = newWidget.id
        newWidget.options.label = newWidget.options.label || newWidget.type.toLowerCase()
      }

      delete newWidget.displayName
      this.emitEvent('canvas-add-field', newWidget.options.name)

      return newWidget
    },

    buildColsOfGrid(gridCon, colNum, colSpan) {
      const newSpan = !!colSpan ? colSpan : 24 / colNum
      for (let i = 0; i < colNum; i++) {
        let newCol = deepClone(this.getContainerByType('grid-col'))
        let tmpId = generateId()
        newCol.id = 'grid-col-' + tmpId
        newCol.options.name = 'gridCol' + tmpId
        newCol.options.span = newSpan
        newCol.options.md = newSpan
        newCol.options.sm = newSpan
        newCol.options.xs = newSpan
        gridCon.cols.push(newCol)
      }
    },

    copyNewContainerWidget(origin) {
      let newCon = deepClone(origin)
      newCon.id = newCon.type.replace(/-/g, '') + generateId()
      newCon.options.name = newCon.id
      if (newCon.options.hasOwnProperty('label')) {
        newCon.options.label = newCon.id
      }

      if (newCon.type === 'grid') {
        /*if (newCon.alias === 'column-1-grid') {
          this.buildColsOfGrid(newCon, 1)
        } else if (newCon.alias === 'column-2-grid') {
          this.buildColsOfGrid(newCon, 2)
        } else if (newCon.alias === 'column-3-grid') {
          this.buildColsOfGrid(newCon, 3)
        } else if (newCon.alias === 'column-4-grid') {
          this.buildColsOfGrid(newCon, 4)
        }*/
      } else if (newCon.type === 'table') {
        let newRow = {
          cols: [],
          id: undefined, merged: undefined,

        }
        newRow.id = 'table-row-' + generateId()
        newRow.merged = false
        let newCell = deepClone(this.getContainerByType('table-cell'))
        newCell.id = 'table-cell-' + generateId()
        newCell.options.name = newCell.id
        newCell.merged = false
        newCell.options.colspan = 1
        newCell.options.rowspan = 1
        newRow.cols.push(newCell)
        newCon.rows.push(newRow)
      } else if (newCon.type === 'tab') {
        let newTabPane = deepClone(this.getContainerByType('tab-pane'))
        newTabPane.id = 'tab-pane-' + generateId()
        newTabPane.options.name = 'tab1'
        newTabPane.options.label = 'tab 1'
        newCon.tabs.push(newTabPane)
      } else if (newCon.type === 'grid-sub-form') {
        const col2Grid = deepClone(this.getContainerByType('grid'))
        col2Grid.id = newCon.type.replace(/-/g, '') + generateId()
        col2Grid.options.name = col2Grid.id
        this.buildColsOfGrid(col2Grid, 4, 12)
        newCon.widgetList.push(col2Grid)
      }

      delete newCon.displayName
      delete newCon.commonFlag
      return newCon
    },

    addContainerByDbClick(container) {
      let newCon = this.copyNewContainerWidget(container)
      this.widgetList.push(newCon)
      this.setSelected(newCon)
    },

    addFieldByDbClick(widget) {
      let newWidget = this.copyNewFieldWidget(widget)
      if (!!this.selectedWidget && this.selectedWidget.type === 'tab') {
        //获取当前激活的tabPane
        let activeTab = this.selectedWidget.tabs[0]
        this.selectedWidget.tabs.forEach((tabPane) => {
          if (!!tabPane.options.active) {
            activeTab = tabPane
          }
        })

        !!activeTab && activeTab.widgetList.push(newWidget)
      } else if (!!this.selectedWidget && !!this.selectedWidget.widgetList) {
        this.selectedWidget.widgetList.push(newWidget)
      } else {
        this.widgetList.push(newWidget)
      }

      this.setSelected(newWidget)
      this.emitEvent('canvas-add-field', newWidget.options.name)
      this.emitHistoryChange()
    },

    findDashboardContainer() {
      if (this.widgetList.length < 1) {
        console.error('Dashboard container not found')
        return null
      }

      let dashboardCon = null
      this.widgetList.forEach((w) => {
        if (w.type === 'dashboard-container') {
          dashboardCon = w
        }
      })

      if (!dashboardCon) {
        console.error('Dashboard container not found')
        return null
      } else {
        return dashboardCon
      }
    },

    addChartContainerByDbClick(container) {
      const dbCon = this.findDashboardContainer()
      if (dbCon) {
        const newCon = deepClone(container)
        newCon.id = 'chartCon' + generateId()
        newCon.options.name = newCon.id

        const ccLayout = {
          x: newCon.options.x,
          y: newCon.options.y,
          w: newCon.options.w,
          h: newCon.options.h,
          i: newCon.id,
        }
        dbCon.options.layout.push(ccLayout)
        dbCon.widgetList.push(newCon)

        this.setSelected(newCon)
        this.emitHistoryChange()
      }
    },

    addChartByDbClick(chart) {
      const dbCon = this.findDashboardContainer()
      if (dbCon) {
        const newChart = deepClone(chart)
        newChart.id = 'chart' + generateId()
        newChart.options.name = newChart.id

        const chartLayout = {
          x: newChart.options.x,
          y: newChart.options.y,
          w: newChart.options.w,
          h: newChart.options.h,
          i: newChart.id,
        }
        dbCon.options.layout.push(chartLayout)
        dbCon.widgetList.push(newChart)

        this.setSelected(newChart)
        this.emitHistoryChange()
      }
    },

    deleteColOfGrid(gridWidget, colIdx) {
      if (!!gridWidget && !!gridWidget.cols) {
        gridWidget.cols.splice(colIdx, 1)
      }
    },

    insertNewColOfGrid(gridWidget, colIdx) {
      const cols = gridWidget.cols
      let newGridCol = deepClone(this.getContainerByType('grid-col'))
      let tmpId = generateId()
      newGridCol.id = 'grid-col-' + tmpId
      newGridCol.options.name = 'gridCol' + tmpId
      if (!!cols && cols.length > 0) {
        let spanSum = 0
        cols.forEach((col) => {
          spanSum += col.options.span
        })

        if (spanSum >= 24) {
          console.log('列栅格之和超出24')
          gridWidget.cols.splice(colIdx + 1, 0, newGridCol)
        } else {
          newGridCol.options.span = 24 - spanSum > 12 ? 12 : 24 - spanSum
          gridWidget.cols.splice(colIdx + 1, 0, newGridCol)
        }
      } else {
        gridWidget.cols = [newGridCol]
      }
    },

    addNewColOfGrid(gridWidget) {
      const cols = gridWidget.cols
      let newGridCol = deepClone(this.getContainerByType('grid-col'))
      let tmpId = generateId()
      newGridCol.id = 'grid-col-' + tmpId
      newGridCol.options.name = 'gridCol' + tmpId
      return newGridCol
    },

    addTabPaneOfTabs(tabsWidget) {
      const tabPanes = tabsWidget.tabs
      let newTabPane = deepClone(this.getContainerByType('tab-pane'))
      newTabPane.id = 'tab-pane-' + generateId()
      newTabPane.options.name = newTabPane.id
      newTabPane.options.label = 'tab ' + (tabPanes.length + 1)
      tabPanes.push(newTabPane)
    },

    deleteTabPaneOfTabs(tabsWidget, tpIdx) {
      tabsWidget.tabs.splice(tpIdx, 1)
    },

    emitEvent(evtName, evtData) {
      //于兄弟组件发射事件
      eventBus.$emit(evtName, evtData)
    },

    handleEvent(evtName, callback) {
      //用于兄弟组件接收事件
      eventBus.$on(evtName, (data) => callback(data))
    },

    setCssClassList(cssClassList) {
      this.cssClassList = cssClassList
    },

    getCssClassList() {
      return this.cssClassList
    },

    registerFormWidget(formWidget) {
      this.formWidget = formWidget
    },

    initHistoryData() {
      // if (!window.__MICRO_APP_ENVIRONMENT__) {
        this.loadFormContentFromStorage()
      // }
      this.historyData.index++
      this.historyData.steps[this.historyData.index] = {
        widgetList: deepClone(this.widgetList),
        formConfig: deepClone(this.formConfig),
      }
    },

    emitHistoryChange() {
      if (this.historyData.index === this.historyData.maxStep - 1) {
        this.historyData.steps.shift()
      } else {
        this.historyData.index++
      }

      this.historyData.steps[this.historyData.index] = {
        widgetList: deepClone(this.widgetList),
        formConfig: deepClone(this.formConfig),
      }

      this.saveFormContentToStorage()

      if (this.historyData.index < this.historyData.steps.length - 1) {
        this.historyData.steps = this.historyData.steps.slice(0, this.historyData.index + 1)
      }
    },

    saveCurrentHistoryStep() {
      this.historyData.steps[this.historyData.index] = deepClone({
        widgetList: this.widgetList,
        formConfig: this.formConfig,
      })

      this.saveFormContentToStorage()
    },

    undoHistoryStep() {
      if (this.historyData.index !== 0) {
        this.historyData.index--
      }

      this.widgetList = deepClone(this.historyData.steps[this.historyData.index].widgetList)
      this.formConfig = deepClone(this.historyData.steps[this.historyData.index].formConfig)
    },

    redoHistoryStep() {
      if (this.historyData.index !== this.historyData.steps.length - 1) {
        this.historyData.index++
      }

      this.widgetList = deepClone(this.historyData.steps[this.historyData.index].widgetList)
      this.formConfig = deepClone(this.historyData.steps[this.historyData.index].formConfig)
    },

    undoEnabled() {
      return this.historyData.index > 0 && this.historyData.steps.length > 0
    },

    redoEnabled() {
      return this.historyData.index < this.historyData.steps.length - 1
    },

    saveFormContentToStorage() {
      window.localStorage.setItem('widget__list__backup', JSON.stringify(this.widgetList))
      window.localStorage.setItem('form__config__backup', JSON.stringify(this.formConfig))
    },
    loadFormContentFromStorage() {
      let widgetListBackup = window.localStorage.getItem('widget__list__backup')
      if (!!widgetListBackup) {
        this.widgetList = JSON.parse(widgetListBackup)
      }

      let formConfigBackup = window.localStorage.getItem('form__config__backup')
      if (!!formConfigBackup) {
        //this.formConfig = JSON.parse(formConfigBackup)
        overwriteObj(
          this.formConfig,
          JSON.parse(formConfigBackup),
        ) /* 用=赋值，会导致inject依赖注入的formConfig属性变成非响应式 */
      }
    },

    /**
     * 加载当前发布（当前使用）的服务版本信息（不一定是最新版本）
     *
     * 此方法从表单绑定的服务视图(formServiceVersionVO)中获取当前发布的服务版本信息，并执行加载当前服务服务版本信息的操作
     * 它主要用于更新系统中的服务版本数据，以确保系统中的服务信息是当前发布的版本（如果同步的话）
     *
     */
    async loadCurrentServiceVersionVOS() {
      return new Promise(resolve => {
        // TODOLIU 加载当前服务版本
        const promises = this.formConfig.serviceVersionVOs.map(async (svvo: ServiceVersionVOType) => {
          return await getCurrentServiceVersionVOByServiceId(svvo.service.id)
        })
        Promise.all(promises).then((results) => {
          this.currentServiceVersionVOs = results
          // 所有 getCurrentServiceVersionVOByServiceId 调用完成后执行 resolve
          resolve(this.currentServiceVersionVOs)
        }).catch((error) => {
          console.error('Error loading latest service version VOs:', error)
        })
      })

      // getCurrentServiceVersionVOByServiceId()
    },
  }
}
